package cn.microservices.cloud.gateway.filter;

import cn.microservices.cloud.gateway.util.FilterRequestResponseUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Slf4j
@Component
@AllArgsConstructor
public class SignFilter implements GlobalFilter, Ordered {


    /**
     * 自定义拦截器获取 body参数
     *
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest serverHttpRequest = exchange.getRequest();
        HttpMethod method = serverHttpRequest.getMethod();
        String contentType = serverHttpRequest.getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
        //post请求时，如果是文件上传之类的请求，不修改请求消息体
//        if (method == HttpMethod.POST && (MediaType.APPLICATION_FORM_URLENCODED_VALUE.equalsIgnoreCase(contentType)
//                || MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(contentType))) {
//            return DataBufferUtils.join(exchange.getRequest().getBody())
//                    .flatMap(dataBuffer -> {
//                        DataBufferUtils.retain(dataBuffer);
//                        Flux<DataBuffer> cachedFlux = Flux
//                                .defer(() -> Flux.just(dataBuffer.slice(0, dataBuffer.readableByteCount())));
//                        ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
//                                exchange.getRequest()) {
//                            @Override
//                            public Flux<DataBuffer> getBody() {
//                                return cachedFlux;
//                            }
//                        };
//                        exchange.getAttributes().put(CACHE_REQUEST_BODY_OBJECT_KEY, cachedFlux);
//
//                        return chain.filter(exchange.mutate().request(mutatedRequest).build());
//                    });
//
//        } else {
//            return chain.filter(exchange);
//        }


        //post请求时，如果是文件上传之类的请求，不修改请求消息体
        if (method == HttpMethod.POST && (MediaType.APPLICATION_FORM_URLENCODED_VALUE.equalsIgnoreCase(contentType)
                || contentType.contains(MediaType.APPLICATION_JSON_VALUE))) {
            return DataBufferUtils.join(exchange.getRequest().getBody())
                    .flatMap(dataBuffer -> {
                        DataBufferUtils.retain(dataBuffer);
                        Flux<DataBuffer> cachedFlux = Flux
                                .defer(() -> Flux.just(dataBuffer.slice(0, dataBuffer.readableByteCount())));
                        ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
                                exchange.getRequest()) {
                            @Override
                            public Flux<DataBuffer> getBody() {
                                return cachedFlux;
                            }
                        };
                        exchange.getAttributes().put(FilterRequestResponseUtil.CACHE_REQUEST_BODY_OBJECT_KEY, cachedFlux);

                        return chain.filter(exchange.mutate().request(mutatedRequest).build());
                    });

        } else {
            return chain.filter(exchange);
        }
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
//
//    @Override
//    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//        return handleParameter(exchange, chain);
//    }
//
//    /**
//     * 处理请求(添加全局类参数)
//     *
//     * @param exchange
//     * @param chain
//     * @return
//     */
//    private Mono<Void> handleParameter(ServerWebExchange exchange, GatewayFilterChain chain) {
//        ServerHttpRequest serverHttpRequest = exchange.getRequest();
//        HttpMethod method = serverHttpRequest.getMethod();
//        String contentType = serverHttpRequest.getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
//        //post请求时，如果是文件上传之类的请求，不修改请求消息体
//        if (method == HttpMethod.POST && (MediaType.APPLICATION_FORM_URLENCODED_VALUE.equalsIgnoreCase(contentType)
//                || MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(contentType))) {
//            //从请求里获取Post请求体
//            String bodyStr = resolveBodyFromRequest(serverHttpRequest);
////===============================================这行bodyStr为null======================================================================
//            // 这种处理方式，必须保证post请求时，原始post表单必须有数据过来，不然会报错
//            if (StringUtils.isBlank(bodyStr)) {
//                ServerHttpResponse response = exchange.getResponse();
//                response.setStatusCode(HttpStatus.BAD_REQUEST);
//                return response.setComplete();
//            }
//
//
//            //下面的将请求体再次封装写回到request里，传到下一级，否则，由于请求体已被消费，后续的服务将取不到值
//            URI uri = serverHttpRequest.getURI();
//            URI newUri = UriComponentsBuilder.fromUri(uri).build(true).toUri();
//            ServerHttpRequest request = exchange.getRequest().mutate().uri(newUri).build();
//            DataBuffer bodyDataBuffer = stringBuffer(bodyStr);
//            Flux<DataBuffer> bodyFlux = Flux.just(bodyDataBuffer);
//
//            // 定义新的消息头
//            HttpHeaders headers = new HttpHeaders();
//            headers.putAll(exchange.getRequest().getHeaders());
//
//            // 由于修改了传递参数，需要重新设置CONTENT_LENGTH，长度是字节长度，不是字符串长度
//            int length = bodyStr.getBytes().length;
//            headers.remove(HttpHeaders.CONTENT_LENGTH);
//            headers.setContentLength(length);
//
//            // 设置CONTENT_TYPE
//            if (StringUtils.isNotBlank(contentType)) {
//                headers.set(HttpHeaders.CONTENT_TYPE, contentType);
//            }
//
//            // 由于post的body只能订阅一次，由于上面代码中已经订阅过一次body。所以要再次封装请求到request才行，不然会报错请求已经订阅过
//            request = new ServerHttpRequestDecorator(request) {
//                @Override
//                public HttpHeaders getHeaders() {
//                    long contentLength = headers.getContentLength();
//                    HttpHeaders httpHeaders = new HttpHeaders();
//                    httpHeaders.putAll(super.getHeaders());
//                    if (contentLength > 0) {
//                        httpHeaders.setContentLength(contentLength);
//                    } else {
//                        // TODO: this causes a 'HTTP/1.1 411 Length Required' on httpbin.org
//                        httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
//                    }
//                    return httpHeaders;
//                }
//
//                @Override
//                public Flux<DataBuffer> getBody() {
//                    return bodyFlux;
//                }
//            };
//
//            //封装request，传给下一级
//            request.mutate().header(HttpHeaders.CONTENT_LENGTH, Integer.toString(bodyStr.length()));
//            return chain.filter(exchange.mutate().request(request).build());
//        } else if (method == HttpMethod.GET) {
//            // 获取原参数
//            URI uri = serverHttpRequest.getURI();
//            StringBuilder query = new StringBuilder();
//            String originalQuery = uri.getRawQuery();
//            if (org.springframework.util.StringUtils.hasText(originalQuery)) {
//                query.append(originalQuery);
//                if (originalQuery.charAt(originalQuery.length() - 1) != '&') {
//                    query.append('&');
//                }
//            }
//            // 替换查询参数
//            URI newUri = UriComponentsBuilder.fromUri(uri)
//                    .replaceQuery(query.toString())
//                    .build(true)
//                    .toUri();
//
//            ServerHttpRequest request = exchange.getRequest().mutate().uri(newUri).build();
//            return chain.filter(exchange.mutate().request(request).build());
//        }
//
//        return chain.filter(exchange);
//    }
//
//
//    /**
//     * 从Flux<DataBuffer>中获取字符串的方法
//     *
//     * @return 请求体
//     */
//    private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) {
//        //获取请求体
//        Flux<DataBuffer> body = serverHttpRequest.getBody();
//
//        AtomicReference<String> bodyRef = new AtomicReference<>();
//        body.subscribe(buffer -> {
//            CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
//            DataBufferUtils.release(buffer);
//            bodyRef.set(charBuffer.toString());
//        });
//        //获取request body
//        return bodyRef.get();
//    }
//
//    /**
//     * 字符串转DataBuffer
//     *
//     * @param value
//     * @return
//     */
//    private DataBuffer stringBuffer(String value) {
//        byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
//        NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
//        DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
//        buffer.write(bytes);
//        return buffer;
//    }
//
//    @Override
//    public int getOrder() {
//        return Ordered.HIGHEST_PRECEDENCE;
//    }

}